#!/bin/bash
### BEGIN INIT INFO
# Provides:          armhwinfo
# Required-Start:
# Required-Stop:     glibc
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Armbian gathering hardware information
### END INIT INFO

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
my_name="${0##*/}"

# Read in basic OS image information
. /etc/armbian-release

collect_information() {
	ifconfig | grep -q eth0 || (ifconfig eth0 up ; sleep 2)
	TMPFILE=$(mktemp /tmp/${0##*/}.XXXXXX)
	trap "sleep 1 ; rm \"${TMPFILE}\" ; exit 0" 0 1 2 3 15
	CPU_ARCH=$(lscpu | awk '/Architecture/ {print $2}')
	DISTRO_ARCH=$(dpkg --print-architecture)
	KERNELID=$(uname -r)
	dmesg >"${TMPFILE}"
} # collect_information

set_io_scheduler() {
	for i in $( lsblk -idn -o NAME | grep -v zram ); do
		read ROTATE </sys/block/$i/queue/rotational
		case ${ROTATE} in
			1) # mechanical drives
				echo cfq >/sys/block/$i/queue/scheduler
				echo -e "[\e[0;32m ok \x1B[0m] Setting cfg I/O scheduler for $i"
				;;
			0) # flash based
				echo noop >/sys/block/$i/queue/scheduler
				echo -e "[\e[0;32m ok \x1B[0m] Setting noop I/O scheduler for $i"
				;;
		esac
	done
} # set_io_scheduler

prepare_temp_monitoring() {
	# still an ugly hack but better do it just once at startup instead of every login
	[ -d /etc/armbianmonitor/datasources ] || mkdir -p -m775 /etc/armbianmonitor/datasources

	# PMIC check
	if [[ -f /sys/power/axp_pmu/pmu/temp ]]; then
		ln -fs /sys/power/axp_pmu/pmu/temp /etc/armbianmonitor/datasources/pmictemp
	elif [[ -f /sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034//temp1_input ]]; then
		ln -fs /sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034/temp1_input \
			/etc/armbianmonitor/datasources/pmictemp
	elif [[ -f /sys/devices/b0170000.i2c/i2c-0/0-0065/atc2603c-hwmon.0/ic_temperature ]]; then
		ln -fs /sys/devices/b0170000.i2c/i2c-0/0-0065/atc2603c-hwmon.0/ic_temperature \
			/etc/armbianmonitor/datasources/pmictemp
	elif [[ -f /sys/class/axppower/ic_temp ]]; then
		ln -fs /sys/class/axppower/ic_temp /etc/armbianmonitor/datasources/pmictemp
	fi

	# SoC temp: check sun7i legacy exception first, then standard path(s)
	if [[ -d "/sys/devices/platform/a20-tp-hwmon" ]]; then
		# sun7i legacy
		ln -fs /sys/devices/platform/a20-tp-hwmon/temp1_input /etc/armbianmonitor/datasources/soctemp
	else
		# all other boards/kernels use the same sysfs node except of Actions Semi S500:
		[[ ${BOARDFAMILY} == s500 ]] && THERMAL_ZONE="thermal_zone1" || THERMAL_ZONE="thermal_zone0"
		ln -fs /sys/devices/virtual/thermal/${THERMAL_ZONE}/temp /etc/armbianmonitor/datasources/soctemp
	fi
	# remove the soctemp node on platforms where kernel support is not yet ready for thermal readouts
	cat /etc/armbianmonitor/datasources/soctemp >/dev/null 2>&1 || rm /etc/armbianmonitor/datasources/soctemp
} # prepare_temp_monitoring

prepare_board() {
	# prevent logrotate from compressing rotated logs when /var/log lives on compressed fs
	CheckDevice=$(for i in /var/log /var / ; do findmnt -n -o SOURCE $i && break ; done)
	[ -n "${CheckDevice}" ] && grep "^${CheckDevice}" /etc/mtab | grep -q compress && \
	for ConfigFile in /etc/logrotate.d/* ; do
		sed -i -e "s/^\s\+compress/\t# compress/" \
		-e "s/^\s\+delaycompress/\t# delaycompress/" "${ConfigFile}"
	done

	# tweak ondemand cpufreq governor settings to increase cpufreq with IO load
	grep -q ondemand /etc/default/cpufrequtils
	if [ $? -eq 0 ]; then
		echo ondemand >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
		cd /sys/devices/system/cpu
		for i in cpufreq/ondemand cpu0/cpufreq/ondemand cpu4/cpufreq/ondemand ; do
			if [ -d $i ]; then
				echo 1 >${i}/io_is_busy
				echo 25 >${i}/up_threshold
				echo 10 >${i}/sampling_down_factor
			fi
		done
	fi

	# IRQ distribution based on $BOARDFAMILY and/or $BOARD_NAME
	case ${BOARDFAMILY} in
		cubox|udoo*) # i.MX6 boards: send Ethernet to cpu3, MMC to cpu1/cpu2 (when available)
			echo 2 >/proc/irq/$(awk -F":" "/mmc0/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -1)/smp_affinity 2>/dev/null
			echo 4 >/proc/irq/$(awk -F":" "/mmc1/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -1)/smp_affinity 2>/dev/null
			echo 8 >/proc/irq/$(awk -F":" "/ethernet/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -1)/smp_affinity 2>/dev/null
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			;;
		mvebu*) # Clearfog/Turris/Helios4/Espressobin: Send network IRQs to cpu1 on both kernels
			for i in $(awk -F':' '/mwlwifi|mvneta|eth0/{print $1}' /proc/interrupts | sed 's/\ //g'); do
				echo 2 >/proc/irq/$i/smp_affinity
			done
			;;
		odroidc1) # ODROID-C0/C1/C1+
			echo 1 >/proc/irq/$(awk -F":" "/usb1/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			for i in $(awk -F':' '/Mali_/{print $1}' </proc/interrupts | sed 's/\ //g'); do echo 1 >/proc/irq/${i}/smp_affinity_list; done
			echo 2 >/proc/irq/$(awk -F":" "/usb2/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 3 >/proc/irq/$(awk -F":" "/eth0/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			;;
		odroidc2|meson64) # S905/S905X/S912: both kernels: send eth0 to cpu3, mmc/usb2 to cpu2 and usb1 to cpu1
			# Basics: http://forum.odroid.com/viewtopic.php?f=115&t=8121#p65777
			for i in $(awk -F':' '/sd_emmc|usb2/{print $1}' </proc/interrupts | sed 's/\ //g'); do
				echo 1 >/proc/irq/$i/smp_affinity_list
			done
			echo 2 >/proc/irq/$(awk -F":" "/usb1/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 3 >/proc/irq/$(awk -F":" "/eth0/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			;;
		odroidxu4) # ODROID XU3/XU4/HC1/MC1/HC2
			echo 2 >/proc/irq/$(awk -F":" "/usb2/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 4 >/proc/irq/$(awk -F":" "/usb3/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 7 >/proc/irq/$(awk -F":" "/usb5/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 16 >/proc/irq/$(awk -F":" "/dw-mci/ {print \$1}" </proc/interrupts | sed 's/\ //g' | tail -1)/smp_affinity
			echo 32 >/proc/irq/$(awk -F":" "/dw-mci/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -1)/smp_affinity
			for i in $(awk -F':' '/11800000.mali/{print $1}' </proc/interrupts | sed 's/\ //g'); do
				echo 64 >/proc/irq/$i/smp_affinity
			done
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			echo 32768 >/proc/sys/net/core/rps_sock_flow_entries
			echo 32768 >/sys/class/net/eth0/queues/rx-0/rps_flow_cnt
			;;
		rockchip) # RK3288: usb1 on cpu1, usb3 (EHCI) on cpu2, eth0 and GPU on cpu3
			echo 2 >/proc/irq/$(awk -F":" "/usb1/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 4 >/proc/irq/$(awk -F":" "/usb3/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 8 >/proc/irq/$(awk -F":" "/eth0/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -n1)/smp_affinity
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			for i in $(awk -F':' '/gpu/{print $1}' /proc/interrupts | sed 's/\ //g'); do
				echo 8 >/proc/irq/$i/smp_affinity
			done
			;;
		rk3328) # ROCK64: GPU on cpu1, USB3 on cpu2, Ethernet on cpu3
			for i in $(awk -F':' '/Mali/{print $1}' </proc/interrupts | sed 's/\ //g'); do
				echo 2 >/proc/irq/$i/smp_affinity
			done
			echo 2 >/proc/irq/$(awk -F":" "/ehci/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 2 >/proc/irq/$(awk -F":" "/ohci/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 4 >/proc/irq/$(awk -F":" "/xhci/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 8 >/proc/irq/$(awk -F":" "/eth0/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			echo 32768 >/proc/sys/net/core/rps_sock_flow_entries
			echo 32768 >/sys/class/net/eth0/queues/rx-0/rps_flow_cnt
			/sbin/ethtool -K eth0 rx off tx off
			;;
		s500) # Roseapple Pi/LeMaker Guitar: send USB IRQs to cpu1/cpu2, DMA0 to cpu2 and Ethernet + SD card to cpu3
			echo 2 >/proc/irq/$(awk -F":" "/usb1/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 4 >/proc/irq/$(awk -F":" "/usb2/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity 2>/dev/null
			echo 4 >/proc/irq/$(awk -F":" "/usb3/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity 2>/dev/null
			echo 4 >/proc/irq/$(awk -F":" "/owl_dma0/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 8 >/proc/irq/$(awk -F":" "/ethernet_mac/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 8 >/proc/irq/$(awk -F":" "/sdcard/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			;;
		s5p6818) # NanoPi M3: dw-mci on cpu1, USB host on cpu2, GbE on cpu3, USB OTG on cpu4, video-codec on cpu5
			for i in $(awk -F':' '/dw-mci/{print $1}' </proc/interrupts | sed 's/\ //g'); do
				echo 1 >/proc/irq/$i/smp_affinity_list
			done
			echo 2 >/proc/irq/$(awk -F":" "/usb3/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 3 >/proc/irq/$(awk -F":" "/eth0/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			echo 4 >/proc/irq/$(awk -F":" "/usb1/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity_list
			for i in $(awk -F':' '/c0080000.video-codec/{print $1}' </proc/interrupts | sed 's/\ //g'); do
				echo 5 >/proc/irq/$i/smp_affinity_list
			done
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			echo 32768 >/proc/sys/net/core/rps_sock_flow_entries
			echo 32768 >/sys/class/net/eth0/queues/rx-0/rps_flow_cnt
			;;
		sun4i|sun5i|rda8810) # only one core, nothing to improve
			:
			;;
		sun6i) # Banana Pi M2: process eth0 on cpu3, SDIO on cpu2, USB on cpu1
			for i in $(awk -F':' '/hcd:usb/{print $1}' /proc/interrupts | sed 's/\ //g'); do
				echo 2 >/proc/irq/$i/smp_affinity
			done
			for i in $(awk -F':' '/sunxi-mmc/{print $1}' /proc/interrupts | sed 's/\ //g'); do
				echo 4 >/proc/irq/$i/smp_affinity
			done
			echo 8 >/proc/irq/$(awk -F":" '/eth0/ {print $1}' </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			;;
		sun7i) # try to redistribute eth0 irq to dedicated core
			echo 2 >/proc/irq/$(awk -F":" '/eth0/ {print $1}' </proc/interrupts | sed 's/\ //g')/smp_affinity 2>/dev/null
			;;
		sun8i*) # H3/R40/V40 boards, try to do the best based on specific board since interfaces vary a lot
			# 10 or 120 sec user feedback that the board is ready after 1st login with 3.4 kernel
			SwapState="$(grep swap /etc/fstab)"
			if [ "X${SwapState}" != "X" ]; then
				(echo heartbeat >/sys/class/leds/*green*/trigger) 2>/dev/null
				[ -f "/root/.not_logged_in_yet" ] && BlinkTime=120 || BlinkTime=10
				(sleep ${BlinkTime} && (echo default-on >/sys/class/leds/*green*/trigger) 2>/dev/null) &
			fi

			# check kernel version for IRQ/module names
			case ${KERNELID} in
				3*)
					# BSP kernel
					GbE="gmac0"; WiFi="wlan0"; USB1="usb2"; USB2="usb3"; USB3="usb4"
					;;
				*)
					# Mainline kernel
					GbE="eth0"; WiFi="wlan0"; USB1="usb3"; USB2="usb4"; USB3="usb5"
					;;
			esac
			# Assign 1st and 2nd USB port to cpu1 and cpu2 on every sun8i board
			echo 2 >/proc/irq/$(awk -F":" "/${USB1}/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 4 >/proc/irq/$(awk -F":" "/${USB2}/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			case ${BOARD_NAME} in
				"Orange Pi+"|"Orange Pi+ 2"|"Orange Pi+ 2E"|"Banana Pi M2*"|"NanoPi M1 Plus")
					# Send GBit Ethernet IRQs to cpu3
					echo 8 >/proc/irq/$(awk -F":" "/${GbE}/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
					echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
					;;
				"NanoPi M1"|"Orange Pi PC Plus"|"Orange Pi PC +"|"Orange Pi PC"|"NanoPi Neo"|"Orange Pi Zero")
					# Send 3rd USB port's IRQs to cpu3
					echo 8 >/proc/irq/$(awk -F":" "/${USB3}/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
					;;
				"Orange Pi Lite"|"NanoPi Air"|"Lime A33"|"Orange Pi Zero Plus 2"*)
					# Send SDIO/mmc IRQs to cpu3
					for i in $(awk -F':' '/sunxi-mmc/{print $1}' </proc/interrupts | sed 's/\ //g'); do
						echo 8 >/proc/irq/$i/smp_affinity
					done
					;;
				"Beelink X2"|"Orange Pi R1")
					# Wifi module reload workaround / fix
					[[ -n $(lsmod | grep 8189es) ]] && rmmod 8189es && modprobe 8189es
					# Send SDIO to cpu1, USB to cpu2, Ethernet to cpu3
					for i in $(awk -F':' '/sunxi-mmc/{print $1}' </proc/interrupts | sed 's/\ //g'); do
						echo 2 >/proc/irq/$i/smp_affinity
					done
					for i in $(awk -F':' '/hcd:usb/{print $1}' </proc/interrupts | sed 's/\ //g'); do
						echo 4 >/proc/irq/$i/smp_affinity
					done
					echo 8 >/proc/irq/$(awk -F":" "/${GbE}/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
					;;
			esac
			;;
		sun50i*|sunxi64*) # A64/H5 based boards like Pine64, OPi PC 2, NanoPi NEO 2
			# Send IRQs for the lower real USB port (usb2) to cpu2 and for the upper (OTG/usb1) to cpu1
			echo 2 >/proc/irq/$(awk -F":" "/usb1/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 4 >/proc/irq/$(awk -F":" "/usb2/ {print \$1}" </proc/interrupts | sed 's/\ //g')/smp_affinity
			echo 8 >/proc/irq/$(awk -F":" "/sunxi-mmc/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -n1)/smp_affinity
			echo 8 >/proc/irq/$(awk -F":" "/eth/ {print \$1}" </proc/interrupts | sed 's/\ //g' | head -n1)/smp_affinity
			echo 7 >/sys/class/net/eth0/queues/rx-0/rps_cpus
			;;
	esac
} # prepare_board

log_hardware_info() {
	Log=/var/log/armhwinfo.log
	[ -f "/etc/logrotate.d/${0##*/}" ] || \
		echo -e "${Log} {\n  rotate 12\n  weekly\n  compress\n  missingok\n  notifempty\n}" \
		> "/etc/logrotate.d/${0##*/}" ; chmod 644 "/etc/logrotate.d/${0##*/}"
	if [ -f ${Log} ]; then
		echo -e "\n\n\n$(date) | ${BOARD_NAME} | ${VERSION} | ${DISTRO_ARCH} | ${CPU_ARCH} | ${KERNELID}" >>${Log}
	else
		echo "$(date) | ${BOARD_NAME} | ${VERSION} | ${DISTRO_ARCH} | ${CPU_ARCH} | ${KERNELID}" >>${Log}
		chmod 644 ${Log}
	fi
	echo -e "\n### dmesg:\n" >>${Log}
	cat "${TMPFILE}" >>${Log}
	echo -e "\n### armbian-release:\n" >>${Log}
	cat /etc/armbian-release >>${Log}
	echo -e "\n### boot environment:\n" >>${Log}
	cat /boot/armbianEnv.txt >>${Log} 2>/dev/null || grep -v "^#" /boot/boot.ini | sed '/^\s*$/d' >>${Log}
	echo -e "\n### lsusb:\n" >>${Log}
	lsusb 2>/dev/null >>${Log}
	echo -e "\n### lscpu:\n" >>${Log}
	lscpu >>${Log}
	echo -e "\n### cpuinfo:\n" >>${Log}
	cat /proc/cpuinfo >>${Log}
	echo -e "\n### meminfo:\n" >>${Log}
	cat /proc/meminfo >>${Log}
	if [ -x /sbin/ip ]; then
		echo -e "\n### ip addr:\n" >>${Log}
		/sbin/ip r s >>${Log} ; /sbin/ip a >>${Log}
		echo " " >>${Log}
	else
		echo -e "\n### ifconfig:\n" >>${Log}
		ifconfig >>${Log}
	fi
	echo -e "### partitions:\n" >>${Log}
	egrep -v " ram| zram" /proc/partitions >>${Log}
	echo -e "\n### df:\n" >>${Log}
	df -h >>${Log}
	which zpool >/dev/null 2>&1 && echo -e "\n### zpools:\n\n$(zpool list)\n\n### zfs datasets:\n\n$(zfs list)" >>${Log}
	echo -e "\n### lsblk:\n" >>${Log}
	lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,UUID | grep -v "^zram" >>${Log}
	echo -e "\n### mtab:\n" >>${Log}
	egrep '^/dev/|\ zfs\ ' /etc/mtab | egrep -v "log2ram|folder2ram" | sort >>${Log}
	[[ -e /boot/script.bin ]] && echo -e "\n### /boot/script.bin --> $(readlink /boot/script.bin)" >>${Log}
	get_flash_information >>${Log}
	(echo -e "\n### Boot system health:\n" >>${Log} ; armbianmonitor -s | egrep "^Time|^[0-9]" >>${Log}) &
} # log_hardware_info

get_flash_information() {
	# http://www.bunniestudios.com/blog/?page_id=1022
	find /sys -name oemid | while read Device ; do
		DeviceNode="${Device%/*}"
		DeviceName="${DeviceNode##*/}"
		echo -e "\n### ${DeviceName} info:\n"
		find "${DeviceNode}" -maxdepth 1 -type f | while read ; do
			NodeName="${REPLY##*/}"
			echo -e "$(printf "%20s" ${NodeName}): $(cat "${DeviceNode}/${NodeName}" | tr '\n' " ")"
		done
	done
} # get_flash_information

show_motd_warning() {
cat > /etc/update-motd.d/90-warning <<EOT
#!/bin/bash
echo -e "\e[0;91mAttention:\x1B[0m $1\n"
rm "\$0"
EOT
chmod +x /etc/update-motd.d/90-warning
} # show_motd_warning

check_sd_card_speed() {
	# function that checks on 3rd boot whether firstrun script made a quick benchmark
	# and displays a motd warning when _random_ I/O is below some tresholds.
	if [ -f /var/log/armhwinfo.log ]; then
		RebootCount=$(grep -c '^### df:' /var/log/armhwinfo.log)
		if [ ${RebootCount} -eq 2 ]; then
			# check whether iozone data has been collected
			IozoneResults="$(awk -F" " '/^### quick iozone test/ {print $10"\t"$11}' </var/log/armhwinfo.log)"
			if [ "X${IozoneResults}" != "X" ]; then
				set ${IozoneResults}
				Readspeed=$1
				Writespeed=$2
				if [ ${Readspeed} -lt 800 -o ${Writespeed} -lt 400 ]; then
					show_motd_warning "Your SD card seems to be very slow. Please check performance using armbianmonitor -c"
				fi
			fi
		fi
	fi
} # check_sd_card_speed

add_usb_storage_quirks() {
	# check for /boot/armbianEnv.txt existence
	[ -f /boot/armbianEnv.txt ] || return

	# preserve old contents if existent
	awk -F"=" '/^usbstoragequirks/ {print $2}' </boot/armbianEnv.txt | tr -d -c '[:graph:]' >${TMPFILE}

	# UAS blacklist Norelsys NS1068X and NS1066X since broken. Can be removed once
	# they're blacklisted upstream
	[ -s ${TMPFILE} ] || echo "0x2537:0x1066:u,0x2537:0x1068:u" >${TMPFILE}

	# check for connected Seagate or WD HDD enclosures and blacklist them all
	lsusb | awk -F" " '{print "0x"$6}' | sed 's/:/:0x/' | sort | uniq | while read ; do
		case ${REPLY} in
			"0x0bc2:"*|"0x1058:"*)
				grep -q "${REPLY}" ${TMPFILE} || sed -i "1 s/\$/,${REPLY}:u/" ${TMPFILE}
				;;
		esac
	done

	read USBQUIRKS <${TMPFILE}
	sed -i '/^usbstoragequirks/d' /boot/armbianEnv.txt
	echo "usbstoragequirks=${USBQUIRKS}" >>/boot/armbianEnv.txt
	# Make sure /boot/armbianEnv.txt is completely written to disk given
	# we flush to disk infrequently and corruption of this file can have
	# nasty side-effects
	sync
	if [ -f /sys/module/usb_storage/parameters/quirks ]; then
		echo ${USBQUIRKS} >/sys/module/usb_storage/parameters/quirks
	fi
} # add_usb_storage_quirks

activate_zram() {
	# Do not interfere with already present config-zram package
	dpkg -l | grep -q 'zram-config' && return

	# Load zram module with n instances (one per CPU core, 4 are the maximum)
	cpu_cores=$(grep -c '^processor' /proc/cpuinfo | sed 's/^0$/1/')
	[[ ${cpu_cores} -gt 4 ]] && zram_devices=4 || zram_devices=${cpu_cores}
	module_args="$(modinfo zram | awk -F" " '/num_devices/ {print $2}' | cut -f1 -d:)"
	[[ -n ${module_args} ]] && modprobe zram ${module_args}=${zram_devices} || return

	# Use half of the real memory by default --> 1/${ram_divisor}
	ram_divisor=2
	mem_info=$(LC_ALL=C free -w 2>/dev/null | grep "^Mem" || LC_ALL=C free | grep "^Mem")
	memory_total=$(awk '{printf("%d",$2*1024)}' <<<${mem_info})
	mem_per_zram_device=$(( ${memory_total} / ${zram_devices} / ${ram_divisor} ))

	for (( i=0; i<zram_devices; i++ )); do
		echo -n ${mem_per_zram_device} > /sys/block/zram${i}/disksize
		[[ -f /sys/block/zram${i}/comp_algorithm ]] && echo lz4 >/sys/block/zram${i}/comp_algorithm 2>/dev/null
		mkswap /dev/zram${i}
		swapon -p 5 /dev/zram${i}
	done
	echo -e "\n### Activated ${zram_devices} zram swap devices with ${mem_per_zram_device} MB each\n" >>${Log}
} # activate_zram

case $1 in
	*start*)
		# set optimal disk scheduler settings
		set_io_scheduler &

		# check sd card speed once on 3rd boot too warn for too slow media
		check_sd_card_speed &

		# get hardware information and rely on contents of /etc/armbian-release
		collect_information

		# hardware preparation
		prepare_board &
		prepare_temp_monitoring &
		# activate_zram &

		# display message, log hardware id to file, write log
		echo -e "[\e[0;32m ok \x1B[0m] Starting ARM hardware info: ${BOARD_NAME} (${VERSION})"
		echo $BOARD_NAME >/var/run/machine.id # we should leave this, maybe users depend on it
		if [ $? -ne 0 ]; then
			# most probably readonly fs. We'll try to warn the user.
			show_motd_warning "It seems the rootfs is readonly at the moment. Please check your SD card for errors"
		fi

		# check whether auto detection override exists and if true use this for machine.id
		[ -f /root/.machine.id ] && cat /root/.machine.id >/var/run/machine.id
		log_hardware_info
		add_usb_storage_quirks
		;;
	*stop*)
		case ${BOARDFAMILY} in
			sun?i)
			# redefine green led to blink until shutdown, try to switch OTG port to host
			(echo heartbeat >/sys/class/leds/*green*/trigger) 2>/dev/null
			echo 0 > /sys/bus/platform/devices/sunxi_usb_udc/otg_role 2>/dev/null
			;;
		esac
		# some kernel modules are known to crash the kernel on shutdown (an example
		# is the mass storage gadget module at least on sun7i). We try to unload as
		# much modules as possible to minimize such situations:
		/sbin/modprobe -r $(cut -f1 -d' ' </proc/modules)
		# shutdown logging
		echo -e "\n### shutdown:\n\n$(iostat -p zram0)\n\n$(vmstat -w)\n\n$(free -h)\n\n$(dmesg | tail -n 100)" >>/var/log/armhwinfo.log
		logger -i -t ${my_name} "Sane shutdown"
		sync
		;;
esac
